{-# LANGUAGE DeriveDataTypeable #-}

module Main where

import Data.Char
import Data.List
import Data.Data
import Data.Generics.Text (gshow)
import Text.Html

main :: IO ()
main = print $ renderData (Person "Rob" "Koe" "Mr" 25)

data Person = Person {
    firstName :: String,
    lastName :: String,
    title :: String,
    age :: Int
} deriving (Read, Show, Typeable, Data)

data Address = Address {
        street :: String,
        city :: String,
        state :: String,
        zipCode :: String
} deriving (Read, Show, Typeable, Data)

renderFieldName :: String -> String
renderFieldName s = cap . unwords $ map uncap (groupBy (\_ -> not . isUpper) s)
    where cap (x : xs) = toUpper x : xs
          cap [] = []
          uncap (x : xs) = toLower x : xs
          uncap [] = []

introspectData :: Data a => a -> [(String, String)]
introspectData a = zip fields (gmapQ gshow a)
    where fields = constrFields $ toConstr a

mapFields :: Data a => a -> ((String, String) -> Html) -> Html
mapFields i renderField = concatHtml $ map renderField (introspectData i)

renderData :: (Data a) => a -> Html
renderData i = thediv << mapFields i renderField
    where renderField (fieldName, val) = thespan << renderFieldName (fieldName ++ ":") +++ thespan << val +++ br

